/* The code examples copyrighted by Nokia Corporation that are included to
 * this material are licensed to you under following MIT-style License:
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include <QDebug>

#include <MApplication>
#include <QDeclarativeView>

#include "signonexample.h"


SignonExample::SignonExample(QDeclarativeContext *context)
{
    authService = new SignOn::AuthService();
    m_identitymodel = new IdentityModel(this);

    m_context = context;
    m_context->setContextProperty("SignonExample", this);
    m_context->setContextProperty("IdentitiesAvailable", m_identitymodel);

    // Initializing
    QStringList initList;
    m_context->setContextProperty("MechsAvailable", QVariant::fromValue(initList));
    m_context->setContextProperty("IdentityMethods", QVariant::fromValue(initList));

    connect(authService, SIGNAL(methodsAvailable(const QStringList&)),
            this, SLOT(methodsAvailable(const QStringList&)));
    connect(authService, SIGNAL(mechanismsAvailable(const QString &, const QStringList&)),
            this, SLOT( mechanismsAvailable(const QString &,  const QStringList&)));
    connect(authService, SIGNAL(error(const SignOn::Error &)),
            this, SLOT(error(const SignOn::Error &)));

    // Query available methods
    authService->queryMethods();;
}

SignonExample::~SignonExample()
{
    delete authService;
    for (int i = 0; i < m_identitymodel->createdIdentitiesQty(); ++i)
        removeIdentity(i);
}

// Adds available methods to combo box and list widget for new identities
void SignonExample::methodsAvailable(const QStringList& mechs)
{
    m_context->setContextProperty("MethodsAvailable", QVariant::fromValue(mechs));
    authService->queryMechanisms(mechs.at(0));
}

// Updates mechanism list for specified method with specified stringlist
void SignonExample::mechanismsAvailable(const QString &method, const QStringList& mechs)
{
    Q_UNUSED(method);
    m_context->setContextProperty("MechsAvailable", QVariant::fromValue(mechs));
}

// Identity was removed, query for new list
void SignonExample::identityRemoved()
{
    QStringList initList;
    m_context->setContextProperty("IdentityMethods", QVariant::fromValue(initList));
    m_identitymodel->removeIdentity(m_removeIndex);
}

// We got list of methods, add them to the list
void SignonExample::identityMethodsAvailable(const QStringList &methods)
{
    m_context->setContextProperty("IdentityMethods", QVariant::fromValue(methods));
}

// Credentials successfully stored, show message to user
void SignonExample::credentialsStored(const quint32 id)
{
    m_identitymodel->addIdentity(id, m_info->caption());
}

void SignonExample::showIdentityMethods(int index)
{
    QStringList initList;
    m_context->setContextProperty("IdentityMethods", QVariant::fromValue(initList));

    if (index < 0)
        return;

    qint32 id = m_identitymodel->identityID(index);
    SignOn::Identity *identity;
    identity = SignOn::Identity::existingIdentity(id);
    connect(identity, SIGNAL(methodsAvailable(const QStringList &)),
            this, SLOT(identityMethodsAvailable(const QStringList &)));

    identity->queryAvailableMethods();
}

void SignonExample::sessionResponse(const SignOn::SessionData &sessionData)
{
    Q_UNUSED(sessionData);
    qDebug("response");
}

// Error occured, alert user.
void SignonExample::error(const SignOn::Error &err)
{
    m_error = err.message();
    emit showError();
}

// Query available mechanisms for given method
void SignonExample::showAvailableMechanisms(const QString & method)
{
    authService->queryMechanisms(method);
}

void SignonExample::createIdentity(QString myCaption, QString myUserName, QString myPassword, QString myMethod)
{
    SignOn::Identity *identity;

    QString caption = myCaption;
    QString username = myUserName;
    QMap<SignOn::MethodName, SignOn::MechanismsList>  methods;
    methods.insert(myMethod, QStringList());

    m_info = new SignOn::IdentityInfo(caption, username, methods);
    m_info->setSecret(myPassword);

    identity = SignOn::Identity::newIdentity(*m_info);

    connect(identity, SIGNAL(credentialsStored(const quint32)),
            this, SLOT(credentialsStored(const quint32)));

    connect(identity, SIGNAL(error(const SignOn::Error &)),
            this, SLOT(error(const SignOn::Error &)));

    identity->storeCredentials(*m_info);
}

void SignonExample::removeIdentity(int index)
{
    if (index < 0)
        return;

    qint32 id = m_identitymodel->identityID(index);

    SignOn::Identity *identity;
    identity = SignOn::Identity::existingIdentity(id);
    connect(identity, SIGNAL(removed()),
            this, SLOT(identityRemoved()));
    connect(identity, SIGNAL(error(const SignOn::Error &)),
            this, SLOT(error(const SignOn::Error &)));
    m_removeIndex = index;

    // Untrusted clients may be blocked from performing this operation.
    // Subject to the security framework restrictions.
    identity->remove();
}

// Challenge button clicked, if item selected, try challenging selected item
void SignonExample::challengeIdentity(int index)
{
    if (index < 0)
        return;

    qint32 id = m_identitymodel->identityID(index);

    SignOn::Identity *identity;
    identity = SignOn::Identity::existingIdentity(id);

    connect(identity, SIGNAL(error(const SignOn::Error &)),
            this, SLOT(error(const SignOn::Error &)));
    connect(identity, SIGNAL(info(const SignOn::IdentityInfo&)),
            this, SLOT(userInfoAvailable(const SignOn::IdentityInfo&)));
    identity->queryInfo();
}

// Identity info available, try logging in if using google
void SignonExample::userInfoAvailable(const SignOn::IdentityInfo& info)
{
    SignOn::AuthSession *session;
    SignOn::SessionData data;
    data.setUserName(info.userName());
    SignOn::Identity *identity = SignOn::Identity::newIdentity(info);

    session = identity->createSession(QString("google"));
    connect(session, SIGNAL(response(const SignOn::SessionData&)),
            this, SLOT(sessionResponse(const SignOn::SessionData&)));
    connect(session, SIGNAL(error(const SignOn::Error &)),
            this, SLOT(error(const SignOn::Error &)));

    session->process(data, QLatin1String("ClientLogin"));
}

QString SignonExample::errorMessage()
{
    return m_error;
}

int main(int argc, char *argv[])
{
    MApplication app(argc, argv);

    QDeclarativeView view;
    SignonExample client(view.rootContext());

    view.setSource(QUrl("qrc:/signon-qt-example.qml"));
    view.showFullScreen();

    return app.exec();
}
